#pragma once
#include <iostream>
#include "Task.hpp"
#include <pthread.h>
#include <queue>
#define NUM 10

class ThreadPool{
    private:
        int num;
        std::queue<TASK> TaskQueue; 
        pthread_mutex_t lock;
        pthread_cond_t cond;
        ThreadPool(int _num = NUM):num(_num){
            pthread_mutex_init(&lock,nullptr);
            pthread_cond_init(&cond,nullptr);
        }
        ThreadPool(const ThreadPool& TP){}
        ~ThreadPool(){
            pthread_mutex_destroy(&lock);
            pthread_cond_destroy(&cond);
        }
        static ThreadPool* tp;
    public:

        static ThreadPool* GetInstance(int _num = NUM){
           static pthread_mutex_t t = PTHREAD_MUTEX_INITIALIZER;
            if(tp == nullptr){
                pthread_mutex_lock(&t);
                if(tp == nullptr){
                    tp = new ThreadPool(_num);
                    tp->InitThreadPool();
                }
                pthread_mutex_unlock(&t);
            }
            return tp;
        }

        static void* ThreadRoutine(void* arg){
            ThreadPool* tp = (ThreadPool*)arg;
            while(true){
                TASK task;
                tp->Lock();
                while(tp->IsEmpty()){
                    tp->ThreadWait();
                }
                tp->PopTask(task);
                tp->Unlock();
                task.ProcessOn();
            }
        }
        bool InitThreadPool(){
            for(int i = 0; i< num;i++){
                pthread_t tid;
                if(0 != pthread_create(&tid,nullptr, ThreadRoutine,this)){
                    LOG(FATAL,"create pthread unsucess");
                    return false;
                }
            }
            return true;
        }
        void Lock(){
            pthread_mutex_lock(&lock);
        }
        void Unlock(){
            pthread_mutex_unlock(&lock);
        }
        void ThreadWait(){
            pthread_cond_wait(&cond,&lock);
        }
        void ThreadWakeup(){
            pthread_cond_signal(&cond);
        }
        bool IsEmpty(){
            return TaskQueue.size() == 0 ? true:false;
        }
        void PushTask(const TASK& task){
            Lock();
            TaskQueue.push(task);
            Unlock();                             
            ThreadWakeup();
            //Routine函数中cond_wait用while循环判断主要是解锁和唤醒代码的顺序问题
            //如果先解锁,那么就会有其他进程抢到锁开始执行后续,但不一定是等待进程在执行
            //所以当后面唤醒等待进程时候,可能会发现任务队列仍然为空,但却继续往下执行,这不符合我们的逻辑
        }
        void PopTask(TASK& task){
            task = TaskQueue.front();
            TaskQueue.pop();
        }
};


ThreadPool* ThreadPool::tp = nullptr;
